home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 January / macformat-020.iso / Shareware City / Developers / SIOD 3.0 / siod.doc < prev    next >
Encoding:
Text File  |  1994-10-01  |  23.9 KB  |  723 lines  |  [TEXT/ttxt]

  1.  *                   COPYRIGHT (c) 1988-1994 BY                             *
  2.  *        PARADIGM ASSOCIATES INCORPORATED, CAMBRIDGE, MASSACHUSETTS.       *
  3.  *        See the source file SLIB.C for more information.                  *
  4.  
  5. Documentation for Release 3.0 1-MAY-1994, George Carrette
  6.  
  7. [Release Notes:]
  8.  
  9. 1.4 This release is functionally the same as release 1.3 but has been
  10. remodularized in response to people who have been encorporating SIOD
  11. as an interpreted extension language in other systems.
  12.  
  13. 1.5 Added the -g flag to enable mark-and-sweep garbage collection.
  14.     The default is stop-and-copy. (Note: changed default to mark-and-sweep)
  15.  
  16. 2.0 Set_Repl_Hooks, catch & throw. 
  17.  
  18. 2.1 Additions to SIOD.SCM: Backquote, cond.
  19.  
  20. 2.2 User Type extension. Read-Macros. (From C-programmer level).
  21.  
  22. 2.3 save-forms. load with argument t, comment character, faster intern.
  23.     -o flag gives obarray size. default 100.
  24.  
  25. 2.4 speed up arithmetic and the evaluator. fixes to siod.scm. no_interrupt
  26.     around calls to C I/O. gen_readr.
  27.  
  28. 2.5 numeric arrays in siod.c
  29.  
  30. 2.6 remodularize .h files, procedure prototypes. gc, eval, print hooks
  31.     now table-driven.
  32.  
  33. 2.7 hash tables, fasload.
  34.  
  35. 2.8 bug fixes.
  36.  
  37. 2.9 added trace.c, fseek, ftell, some fixes.
  38.  
  39. 3.0 Windows NT port. some cleanups. SQL support, more string stuff. 
  40.     Heap management flexibility, default to mark-and-sweep, suggestions
  41.     by some code reviewers for comp.sources.unix.
  42.  
  43. gjc@paradigm.com, gjc@mitech.com
  44. George Carrette
  45.  
  46.    
  47. Paradigm Associates Inc          Phone: 617-492-6079
  48. 29 Putnam Ave, Suite 6
  49. Cambridge, MA 02138
  50.  
  51. [Files:]
  52.  
  53.  siod.h    Declarations 
  54.  siodp.h   private declarations.
  55.  slib.c    scheme library.
  56.  sliba.c   array library.
  57.  siod.c    a main program.
  58.  trace.c   an optional trace package.
  59.  siod.scm  Some scheme code
  60.  pratt.scm A pratt-parser in scheme.
  61.  sql_rdb.* DIGITAL RDB SQL SUPPORT
  62.  sql_oracle.* Oracle Call Interface Support.
  63.  
  64.  
  65. [Motivation:]
  66.  
  67. The most obvious thing one should notice is that this lisp implementation 
  68. is extremely small. For example, the resulting binary executable file 
  69. on a VAX/VMS system with /notraceback/nodebug is 17 kilo-bytes.
  70.  
  71. Small enough to understand, the source file slib.c is 30 kilo-bytes.
  72.  
  73. Small enough to include in the smallest applications which require
  74. command interpreters or extension languages.
  75.  
  76. We also want to be able to run code from the book "Structure and
  77. Interpretation of Computer Programs." 
  78.  
  79. Techniques used will be familiar to most lisp implementors.  Having
  80. objects be all the same size, and having only two statically allocated
  81. spaces simplifies and speeds up both consing and gc considerably.  the
  82. MSUBR hack allows for a modular implementation of tail recursion,     
  83. an extension of the FSUBR that is, as far as I know, original.
  84. The optional stop and copy garbage collector may be selected at runtime.
  85.  
  86. Error handling is rather crude. A topic taken with machine fault,
  87. exception handling, tracing, debugging, and state recovery which we
  88. could cover in detail, but is clearly beyond the scope of this
  89. implementation. Suffice it to say that if you have a good symbolic
  90. debugger you can set a break point at "err" and observe in detail all
  91. the arguments and local variables of the procedures in question, since
  92. there is no casting of data types. For example, if X is an offending
  93. or interesting object then examining X->type will give you the type,
  94. and X->storage_as.cons will show the car and the cdr.
  95.  
  96. [Invocation:]
  97.  
  98. siod [-hXXXXX:[N]] [-iXXXXX] [-gX] [-oXXXXX] [-nXXXXX] [-sXXXXX] [-eXXXXX]
  99.  -h where XXXXX is an integer, to specify the heap size, in obj cells,
  100.     N is the optional number of heaps limit (default 2).
  101.  -i where XXXXX is a filename to load before going into the repl loop.
  102.  -g where X = 1 for stop-and-copy GC, X = 0 for mark-and-sweep.
  103.  -o where XXXXX is the size of the symbol hash table to use, default 100.
  104.  -n where XXXXX is the number of preconsed/interned non-negative numbers.
  105.  -s where XXXXX is the number of bytes of machine recursion stack.
  106.  -e where XXXXX is an expression to evaluate, then exit.
  107.  
  108.   Example:
  109.    siod -isiod.scm -h100000:100
  110.  
  111. [Garbage Collection:]
  112.  
  113. There are two storage management techniques which may be chosen at runtime
  114. by specifying the -g argument flag. 
  115.  
  116.  -g1 is stop-and-copy. This is the simplest and most
  117.      portable implementation. GC is only done at toplevel.
  118.  -g0 (the default) is mark-and-sweep. GC is done at any time, 
  119.      required or requested. However, the implementation is not as portable.
  120.  
  121. If you get strange errors on a machine architecture not listed
  122. then you may be forced to use -g1 until you investigate and contact
  123. the author for advise.
  124.  
  125. Discussion of stop-and-copy follows:
  126.  
  127. As one can see from the source, garbage collection is really quite an easy
  128. thing. The procedure gc_relocate is about 25 lines of code, and
  129. scan_newspace is about 15.
  130.  
  131. The real tricks in handling garbage collection are (in a copying gc):
  132.  (1) keeping track of locations containing objects
  133.  (2) parsing the heap (in the space scanning)
  134.  
  135. The procedure gc_protect is called once (e.g. at startup) on each
  136. "global" location which will contain a lisp object.
  137.  
  138. That leaves the stack. Now, if we had chosen not to use the argument
  139. and return-value passing mechanism provided by the C-language
  140. implementation, (also known as the "machine stack" and "machine
  141. procedure calling mechanism) this lisp would be larger, slower, and
  142. rather more difficult to read and understand. Furthermore it would be
  143. considerably more painful to *add* functionality in the way of SUBR's
  144. to the implementation.
  145.  
  146. Aside from writing a very machine and compiler specific assembling language
  147. routine for each C-language implementation, embodying assumptions about
  148. the placement choices for arguments and local values, etc, we
  149. are left with the following limitation: "YOU CAN GC ONLY AT TOP-LEVEL"
  150.  
  151. However, this fits in perfectly with the programming style imposed in
  152. many user interface implementations including the MIT X-Windows Toolkit.
  153. In the X Toolkit, a callback or work procedure is not supposed to spend
  154. much time implementing the action. Therefore it cannot have allocated
  155. much storage, and the callback trampoline mechanism can post a work
  156. procedure to call the garbage collector when needed.
  157.  
  158. Our simple object format makes parsing the heap rather trivial.
  159. In more complex situations one ends up requiring object headers or markers
  160. of some kind to keep track of the actual storage lengths of objects
  161. and what components of objects are lisp pointers.
  162.  
  163. Because of the usefulness of strings, they were added by default into
  164. SIOD 2.6. The implementation requires a hook that calls the C library
  165. memory free procedure when an object is in oldspace and never
  166. got relocated to newspace. Obviously this slows down the mark-and-sweep
  167. GC, and removes one of the usual advantages it has over mark-and-sweep.
  168.  
  169. Discussion of mark-and-sweep follows:
  170.  
  171. In a mark-and-sweep GC the objects are not relocated. Instead
  172. one only has to LOOK at objects which are referenced by the argument
  173. frames and local variables of the underlying (in this case C-coded)
  174. implementation procedures. If a pointer "LOOKS" like it is a valid
  175. lisp object (see the procedure mark_locations_array) then it may be marked,
  176. and the objects it points to may be marked, as being in-use storage which
  177. is not linked into the freelist in the gc_sweep phase.
  178.  
  179. Another advantage of the mark_and_sweep storage management technique is
  180. that only one heap is required.
  181.  
  182. This main disadvantages are:
  183. (1) start-up cost to initially link freelist.
  184.     (can be avoided by more general but slower NEWCELL code).
  185. (2) does not COMPACT or LOCALIZE the use of storage. This is poor engineering
  186.     practice in a virtual memory environment.
  187. (2) the entire heap must be looked at, not just the parts with useful storage.
  188.  
  189. In general, mark-and-sweep is slower in that it has to look at more
  190. memory locations for a given heap size, however the heap size can
  191. be smaller for a given problem being solved. More complex analysis
  192. is required when READ-ONLY, STATIC, storage spaces are considered.
  193. Additionally the most sophisticated stop-and-copy storage management
  194. techniques take into account considerations of object usage temporality.
  195.  
  196. The technique assumes that all machine registers the GC needs to
  197. look at will be saved by a setjmp call into the save_regs_gc_mark data.
  198.  
  199. [Compilation:]
  200.  
  201. This code (version 2.7) has been compiled and run under the following:
  202. - SUN-IV,      GCC (GNU C)
  203. - VAX/VMS,     VAXC
  204. - MacIntosh,   THINK C 5.0
  205.  
  206. Earlier versions were compiled and run on the AMIGA, Encore, and 4.3BSD.
  207. There are reports that the code will also compile and run under MS-DOS.
  208.  
  209. On all unix machines use (with floating-point flags as needed)
  210.   
  211.   %cc -O -c siod.c
  212.   %cc -O -c slib.c
  213.   %cc -O -c sliba.c
  214.   %cc -o siod siod.o slib.o sliba.o
  215.  
  216. If cc doesn't work, try gcc (GNU C, Free Software Foundation, Cambridge MA).
  217.  
  218. on VAX/VMS:
  219.  
  220.   $ cc siod
  221.   $ cc slib
  222.   $ cc sliba
  223.   $ link siod,slib,sliba,sys$input:/opt
  224.   sys$library:vaxcrtl/share
  225.   $ siod == "$" + F$ENV("DEFAULT") + "SIOD"
  226.  
  227. on AMIGA 500, ignore warning messages about return value mismatches,
  228.   %lc siod.c
  229.   %lc slib.c
  230.   %lc sliba.c
  231.   %blink lib:c.o,siod.o,slib.o,sliba.o to siod lib lib:lcm.lib,lib:lc.lib,lib:amiga.lib
  232.  
  233. in THINK C.
  234.   The siod project must include siod.c,slib.c,slib.c,sliba.c,siodm.c, ANSI.
  235.   The compilation option "require prototypes" should be used.
  236.  
  237. [System:]
  238.  
  239. The interrupts called SIGINT and SIGFPE by the C runtime system are
  240. handled by invoking the lisp error procedure. SIGINT is usually caused
  241. by the CONTROL-C character and SIGFPE by floating point overflow or underflow.
  242.  
  243. [Syntax:]
  244.  
  245. The only special characters are the parenthesis and single quote.
  246. Everything else, besides whitespace of course, will make up a regular token.
  247. These tokens are either symbols or numbers depending on what they look like.
  248. Dotted-list notation is not supported on input, only on output.
  249.  
  250. [Special forms:]
  251.  
  252. The CAR of a list is evaluated first, if the value is a SUBR of type 9 or 10
  253. then it is a special form.
  254.  
  255. (define symbol value) is presently like (set! symbol value).
  256.  
  257. (define (f . arglist) . body) ==> (define f (lambda arglist . body))
  258.  
  259. (lambda arglist . body) Returns a closure.
  260.  
  261. (if pred val1 val2) If pred evaluates to () then val2 is evaluated else val1.
  262.  
  263. (begin . body) Each form in body is evaluated with the result of the last
  264. returned.
  265.  
  266. (set! symbol value) Evaluates value and sets the local or global value of
  267. the symbol.
  268.  
  269. (or x1 x2 x3 ...) Returns the first Xn such that Xn evaluated non-().
  270.  
  271. (and x1 x2 x3 ...) Keeps evaluating Xj until one returns (), or Xn.
  272.  
  273. (quote form). Input syntax 'form, returns form without evaluation.
  274.  
  275. (let pairlist . body) Each element in pairlist is (variable value).
  276. Evaluates each value then sets of new bindings for each of the variables,
  277. then evaluates the body like the body of a progn. This is actually
  278. implemented as a macro turning into a let-internal form.
  279.  
  280. (the-environment) Returns the current lexical environment.
  281.  
  282. [Macro Special forms:]
  283.  
  284. If the CAR of a list evaluates to a symbol then the value of that symbol
  285. is called on a single argument, the original form. The result of this
  286. application is a new form which is recursively evaluated.
  287.  
  288. [Built-In functions:]
  289.  
  290. These are all SUBR's of type 4,5,6,7, taking from 0 to 3 arguments
  291. with extra arguments ignored, (not even evaluated!) and arguments not
  292. given defaulting to (). SUBR's of type 8 are lexprs, receiving a list
  293. of arguments. Order of evaluation of arguments will depend on the
  294. implementation choice of your system C compiler.
  295.  
  296. consp cons car cdr set-car! set-cdr!
  297.  
  298. number? + - * / < > eqv?
  299. The arithmetic functions all take two arguments.
  300.  
  301. eq?, pointer objective identity. (Use eqv? for numbers.)
  302.  
  303. symbolconc, takes symbols as arguments and appends them. 
  304.  
  305. symbol?
  306.  
  307. symbol-bound? takes an optional environment structure.
  308. symbol-value also takes optional env.
  309. set-symbol-value also takes optional env.
  310.  
  311. env-lookup takes a symbol and an environment structure. If it returns
  312. non-nil the CAR will be the value of the symbol.
  313.  
  314. assq
  315.  
  316. read,print
  317.  
  318. eval, takes a second argument, an environment.
  319.  
  320. copy-list. Copies the top level conses in a list.
  321.  
  322. (apropos) returns a copy of the list of the symbols that have been interned.
  323. (apropos "m") returns a list of symbols containing "m"
  324. (apropos "m" "x" ...) returns a list containing "m" and "x" and ...
  325.  
  326. gc-status, prints out the status of garbage collection services, the
  327. number of cells allocated and the number of cells free. If given
  328. a () argument turns gc services off, if non-() turns gc services on.
  329. In mark-and-sweep storage management mode the argument only turns on
  330. and off verbosity of GC messages.
  331.  
  332. gc, does a mark-and-sweep garbage collection. If called with argument nil
  333. does not print gc messages during the gc.
  334.  
  335. (allocate-heap) will allocate an additional heap if available.
  336.  
  337. (gc-info n) returns for n = 0 copying? 1 = n-current-heaps 2 = n-max-heaps 
  338. 3 = heap-size 4 = n-free-cells. e.g.
  339.  
  340. (set! *after-gc* '(if (< (gc-info 4) 5000) (allocate-heap)))
  341.  
  342. load, given a filename (which must be a symbol, there are no strings)
  343. will read/eval all the forms in that file. An optional second argument,
  344. if T causes returning of the forms in the file instead of evaluating them.
  345.  
  346. save-forms, given a filename and a list of forms, prints the forms to the
  347. file. 3rd argument is optional, 'a to open the file in append mode.
  348.  
  349. quit, will exit back to the operating system.
  350.  
  351. error, takes a symbol as its first argument, prints the pname of this
  352. as an error message. The second argument (optional) is an offensive
  353. object. The global variable errobj gets set to this object for later
  354. observation. If a (*catch 'errobj ...) is in effect then errors throw
  355. to this tag instead of jumping back to the toplevel read-eval-print loop.
  356.  
  357. null?, not. are the same thing.
  358.  
  359. *catch tag exp, Sets up a dynamic catch frame using tag. Then evaluates exp.
  360.  
  361. *throw tag value, finds the nearest *catch with an EQ tag, and cause it to
  362. return value.
  363.  
  364. [Strings]
  365.  
  366. (number->string x [base]) => "..."
  367. (string->number "..." [base]) => x
  368. (read-from-string "....")
  369. (string-append ...)
  370. (string-search "token" "string") => () or starting index.
  371. (substring "string" start end)
  372. (string-length "foo") => 3
  373. (string-trim "  foo ") => "foo"
  374. (string-trim-left "foo ") => "foo "
  375. (string-trim-right "  foo") => "  foo"
  376. (string-upcase "foo") => "FOO")
  377. (string-downcase "FOO") => "foo"
  378.  
  379. [Procedures in main program siod.c]
  380.  
  381. cfib is the same as standard-fib. You can time it and compare it with
  382. standard-fib to get an idea of the overhead of interpretation.
  383.  
  384. vms-debug invokes the VMS debugger. The one optional argument is
  385. a string of vms-debugger commands. To show the current call
  386. stack and then continue execution:
  387.  
  388.     (vms-debug "set module/all;show calls;go") 
  389.  
  390. Or, to single step and run at the same time:
  391.  
  392.     (vms-debug "for i=1 to 100 do (STEP);go")
  393.  
  394. Or, to set up a breakpoint on errors:
  395.  
  396.     (vms-debug "set module slib;set break err;go")
  397.  
  398.  
  399. [Utility procedures in siod.scm:]
  400.  
  401. Shows how to define macros.
  402.  
  403. cadr,caddr,cdddr,replace,list.
  404.  
  405. (defvar variable default-value)
  406.  
  407. And for us old maclisp hackers, setq and defun, and progn, etc.
  408.  
  409. call-with-current-continuation (Must load siod.scm)
  410. Implemented in terms of *catch and *throw. So upward continuations
  411. are not allowed.
  412.  
  413. A simple backquote (quasi-quote) implementation.
  414. Must load siod.scm
  415.  
  416. cond, a macro.
  417.  
  418. append
  419.  
  420. nconc
  421.  
  422. [TRACE]
  423.  
  424. (trace procedure1 procedure2 ...)
  425. (untrace procedure1 procedure2 ...)
  426.  
  427. Note: * trace is an fsubr, and can be used on internal procedures too.
  428.       * only interpreted procedures (non-subrs) can be traced.
  429.  
  430. (define (f x)
  431.    (let ((g (lambda () ...)))
  432.      (trace g)
  433.      (g)))
  434.  
  435. [Advanced I/O]
  436.  
  437. Efficient binary I/O may be used to save non-cicular data structures.
  438. See siod.scm for definitions of fasload and fasdump.
  439.  
  440. (fopen filename mode) => file
  441. (fclose file)
  442. (getc file)
  443. (putc char file)
  444.  
  445. (fread size file) => string    ;; conses a new string.
  446. (fread string file) => length  ;; stores into existing string.
  447. (fwrite string file)
  448.  
  449. (fseek file offset direction)
  450. (ftell file) => offset
  451.  
  452. Note: By combining the use of fast-print and fast-read with and without
  453.       the use of tables, with clever use of ftell and fseek, it is possible
  454.       to implement an efficient database of lisp expressions.
  455.  
  456. (fast-read table) => expression
  457. (fast-print expression table)
  458.  
  459. A table is a list containing 3 elements: (<file> <hash-table> <index>)
  460. When doing fast-print the index and hash-table are updated as data
  461. is written to the file. If the index is () then symbol-printing is
  462. not optimized. fast-read uses just the <hash-table> as a way of
  463. looking up previously interned symbols that have been assigned
  464. an index.
  465.  
  466. [A streams implementation:]
  467.  
  468. The first thing we must do is decide how to represent a stream.
  469. There is only one reasonable data structure available to us, the list.
  470. So we might use (<stream-car> <cache-flag> <cdr-cache> <cdr-procedure>)
  471.  
  472. the-empty-stream is just ().
  473.  
  474. empty-stream?
  475.  
  476. head
  477.  
  478. tail
  479.  
  480. cons-stream is a special form. Wraps a lambda around the second argument.
  481.  
  482. *cons-stream is the low-level constructor used by cons-stream.
  483.  
  484. fasload, fasldump. Take the obvious arguments, and are implemented
  485. in terms of fast-read and fast-print.
  486.  
  487. compile-file. 
  488.  
  489. [Arrays:]
  490.  
  491. (cons-array size [type]) Where [type] is double, long, string, lisp or nil.
  492. (aref array index)
  493. (aset array index value) 
  494.  
  495. fasload and fasdump are effective ways of storing and restoring numeric
  496. array data.
  497.  
  498. [Benchmarks:]
  499.  
  500. A standard-fib procedure is included in siod.scm so that everyone will
  501. use the same definition in any reports of speed. Make sure the return
  502. result is correct. use command line argument of
  503.  %siod -h100000 -isiod.scm
  504.  
  505. (standard-fib 10) => 55 ; 795 cons work.
  506. (standard-fib 15) => 610 ; 8877 cons work.
  507. (standard-fib 20) => 6765 ; 98508 cons work.
  508.  
  509. [Porting:]
  510.  
  511. See the #ifdef definition of myruntime, which
  512. should be defined to return a double float, the number of cpu seconds
  513. used by the process so far. It uses the the tms_utime slot, and assumes
  514. a clock cycle of 1/60'th of a second.
  515.  
  516. If your system or C runtime needs to poll for the interrupt signal
  517. mechanism to work, then define INTERRUPT_CHECK to be something
  518. useful.
  519.  
  520. The STACK_LIMIT and STACK_CHECK macros may need to be conditionized.
  521. They currently assume stack growth downward in virtual address.
  522. The subr (%%stack-limit setting non-verbose) may be used to change the
  523. limits at runtime.
  524.  
  525. The stack and register marking code used in the mark-and-sweep GC
  526. is unlikely to work on machines that do not keep the procedure call
  527. stack in main memory at all times. It is assumed that setjmp saves
  528. all registers into the jmp_buff data structure.
  529.  
  530. If the stack is not always aligned (in LISP-PTR sense) then the 
  531. gc_mark_and_sweep procedure will not work properly. 
  532.  
  533. Example, assuming a byte addressed 32-bit pointer machine:
  534.  
  535. stack_start_ptr: [LISP-PTR(4)] 
  536.                  [LISP-PTR(4)]
  537.                  [RANDOM(4)]
  538.                  [RANDOM(2)]
  539.                  [LISP-PTR(4)]
  540.                  [LISP-PTR(4)]
  541.                  [RANDOM(2)]
  542.                  [LISP-PTR(4)]
  543.                  [LISP-PTR(4)]
  544. stack_end:       [LISP-PTR(4)]
  545.  
  546. As mark_locations goes from start to end it will get off proper alignment
  547. somewhere in the middle, and therefore the stack marking operation will
  548. not properly identify some valid lisp pointers.
  549.  
  550. Fortunately there is an easy fix to this. A more aggressive use of
  551. our mark_locations procedure will suffice.
  552.  
  553. For example, say that there might be 2-byte random objects inserted into
  554. the stack. Then use two calls to mark_locations:
  555.  
  556.  mark_locations(((char *)stack_start_ptr) + 0,((char *)&stack_end) + 0);
  557.  mark_locations(((char *)stack_start_ptr) + 2,((char *)&stack_end) + 2);
  558.  
  559. If we think there might be 1-byte random objects, then 4 calls are required:
  560.  
  561.  mark_locations(((char *)stack_start_ptr) + 0,((char *)&stack_end) + 0);
  562.  mark_locations(((char *)stack_start_ptr) + 1,((char *)&stack_end) + 1);
  563.  mark_locations(((char *)stack_start_ptr) + 2,((char *)&stack_end) + 2);
  564.  mark_locations(((char *)stack_start_ptr) + 3,((char *)&stack_end) + 3);
  565.  
  566.  
  567. [Interface to other programs:]
  568.  
  569. If your main program does not want to actually have a read/eval/print
  570. loop, and instead wants to do something else entirely, then use
  571. the routine set_repl_hooks to set up for procedures for:
  572.  
  573.  * putting the prompt "> " and other info strings to standard output.
  574.  
  575.  * reading (getting) an expression
  576.  
  577.  * evaluating an expression
  578.  
  579.  * printing an expression.
  580.  
  581. The routine get_eof_val may be called inside your reading procedure
  582. to return a value that will cause exit from the read/eval/print loop.
  583.  
  584. In order to call a single C function in the context of the repl loop,
  585. you can do the following:
  586.  
  587. int flag = 0;
  588.  
  589. void my_puts(st)
  590.  char *st;
  591. {}
  592.  
  593. LISP my_reader()
  594. {if (flag == 1)
  595.   return(get_eof_val());
  596.  flag == 1;
  597.  return(NIL);}
  598.  
  599. LISP my_eval(x)
  600.  LISP x;
  601. {call_my_c_function();
  602.  return(NIL);}
  603.  
  604. LISP my_print(x)
  605.  LISP x;
  606. {}
  607.  
  608. do_my_c_function()
  609. {set_repl_hooks(my_puts,my_read,my_eval,my_print);
  610.  repl_driver(1, /* or 0 if we do not want lisp's SIGINT handler */
  611.              0);}
  612.  
  613.  
  614. If you need a completely different read-eval-print-loop, for example
  615. one based in X-Window procedures such as XtAddInput, then you may want to
  616. have your own input-scanner and utilize a read-from-string kind of
  617. function.
  618.  
  619. For example, this main program gets a string using fgets, and
  620. evaluates the string without printing any information.
  621.  
  622. #include <stdio.h>
  623. #include <stdlib.h>
  624. #include <string.h>
  625.  
  626. #include "siod.h"
  627.  
  628. void repl_c_string(char *);
  629.  
  630. int main(int argc,char **argv)
  631. {char *local_argv[3];
  632.  char linebuff[256],*ptr;
  633.  local_argv[0] = "siod";
  634.  local_argv[1] = "-h50000";
  635.  local_argv[2] = "-g0";
  636.  print_welcome();
  637.  process_cla(3,local_argv,1);
  638.  print_hs_1();
  639.  init_storage();
  640.  init_subrs();
  641.  init_trace();
  642.  while(fgets(linebuff,sizeof(linebuff),stdin))
  643.    {if (ptr == strchr(linebuff,'\n')) *ptr = 0;
  644.     repl_c_string(linebuff);}
  645.  printf("EXIT\n");}
  646.  
  647. void my_puts(char *st)
  648. {}
  649.  
  650. static char *repl_c_string_arg = NULL;
  651.  
  652. LISP my_read(void)
  653. {LISP s;
  654.  if (repl_c_string_arg == NULL)
  655.    return(get_eof_val());
  656.  s = strcons(strlen(repl_c_string_arg),repl_c_string_arg);
  657.  repl_c_string_arg = NULL;
  658.  return(read_from_string(s));}
  659.  
  660. LISP my_print(LISP x)
  661. {}
  662.  
  663. void repl_c_string(char *str)
  664. {struct repl_hooks h;
  665.  h.repl_puts = my_puts;
  666.  h.repl_read = my_read;
  667.  h.repl_eval = NULL;
  668.  h.repl_print = my_print;
  669.  repl_c_string_arg = str;
  670.  repl_driver(1,1,&h);}
  671.  
  672.  
  673. [User Type Extension:]
  674.  
  675. There are 5 user types currently available. tc_user_1 through tc_user_5.
  676. If you use them then you must at least tell the garbage collector about
  677. them. To do this you must have 4 functions,
  678.  * a user_relocate, takes a object and returns a new copy.
  679.  * a user_scan, takes an object and calls relocate on its subparts.
  680.  * a user_mark, takes an object and calls gc_mark on its subparts or
  681.                 it may return one of these to avoid stack growth.
  682.  * a user_free, takes an object to hack before it gets onto the freelist.
  683.  
  684. set_gc_hooks(type,
  685.              user_relocate_fcn,
  686.              user_scan_fcn,
  687.              user_mark_fcn,
  688.              user_free_fcn,
  689.              &kind_of_gc);
  690.  
  691. kind_of_gc should be a long. It will receive 0 for mark-and-sweep, 1 for
  692. stop-and-copy. Therefore set_gc_hooks should be called AFTER process_cla.
  693. You must specify a relocate function with stop-and-copy. The scan
  694. function may be NULL if your user types will not have lisp objects in them.
  695. Under mark-and-sweep the mark function is required but the free function
  696. may be NULL.
  697.  
  698. See SIOD.C for a very simple string-append implementation example.
  699.  
  700. You might also want to extend the printer. This is optional.
  701.  
  702. set_print_hooks(type,fcn);
  703.  
  704. The fcn receives the object which should be printed to its second
  705. argument, a FILE*.
  706.  
  707. The evaluator may also be extended, with the "application" of user defined
  708. types following in the manner of an MSUBR.
  709.  
  710. Lastly there is a simple read macro facility.
  711.  
  712. void set_read_hooks(char *all_set,char *end_set,
  713.             LISP (*fcn1)(),LISP (*fcn2)())
  714.  
  715. All_set is a string of all read macros. end_set are those
  716. that will end the current token.
  717.  
  718. The fcn1 will receive the character used to trigger
  719. it and the struct gen_readio * being read from. It should return a lisp object.
  720.  
  721. the fnc2 is optional, and is a user hook into the token => lisp object
  722. conversion.
  723.